#pragma once

#include <atomic>
#include <condition_variable>
#include <functional>
#include <memory>
#include <mutex>
#include <queue>
#include <string>

#include "Connection.h"
class ConnectionPool {
public:
    // 单例获取连接池对象 (使用懒汉式线程安全的单例设计模式)
    static ConnectionPool* getInstance();

    // 从连接池中获取一个空闲连接，基于智能指针，自动回收，放回连接池中
    // 通过重定义删除器，自动释放连接时，调用删除器，回收到连接池中
    std::shared_ptr<Connection> getConnection();

private:
    // 私有 构造
    ConnectionPool(const std::string& configFilePath =
                       "mysql.cnf");  // 私有化构造方法 保证单例

    // 加载配置文件，读取数据库连接配置
    bool loadConfigFile(std::string configFilePath);

    // 运行在独立的线程中，专门负责生产新连接
    void produceConnectionTask();

    // 扫描连接池中的所有连接，释放超出最长空闲时间的连接
    void releaseIdleConnection();

private:
    std::string _ip;        // 数据库ip地址
    unsigned short _port;   // 数据库端口号
    std::string _username;  // 数据库用户名
    std::string _password;  // 数据库密码
    std::string _dbname;    // 数据库名称

    int _initSize;           // 连接池初始连接数
    int _maxSize;            // 连接池最大连接数
    int _maxIdleTime;        // 连接最长空闲时间
    int _connectionTimeout;  // 获取连接的超时时间

    // todo 将连接都使用智能指针
    std::queue<Connection*> _connectionQueue;  // 存放数据库连接
    std::atomic_int _connCnt;                  // 队列中连接个数
    std::mutex _queueMtx;  // 保证连接队列的互斥访问
    std::condition_variable _cv;
};
